/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package mbox.model;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import mbox.helper.Utilities;

/**
 *
 * @author Hallucinogen
 */
public class VersionControl {
    public VersionControl() {
        mMetadatas = new ArrayList<Metadata>();
    }

    public VersionControl(VersionControl other) {
        mMetadatas = new ArrayList<Metadata>();

        for (int i = 0; i < other.getMetadatas().size(); ++i)
            mMetadatas.add(new Metadata(other.getMetadatas().get(i)));
    }

    public static VersionControl getVersionControl(String folderPath) {
        VersionControl retval = new VersionControl();
        String protocolFolder = folderPath + "/.ganteng";
        File protocolFile = new File(protocolFolder);

        if (!protocolFile.exists() || !protocolFile.isDirectory())
            protocolFile.mkdirs();

        String[] revList    = protocolFile.list();

        if (revList.length == 0) {
            // create new revision folder
            retval.mVersion = 1;
            retval.evaluateFolder(folderPath);
        } else {
            // evaluate existing
            String lastRev      = revList[revList.length - 1];
            retval.mVersion     = Integer.parseInt(lastRev.substring(0, lastRev.indexOf(".")));

            try {
                ArrayList<Metadata> currentMetadata = Metadata.readMetadatas(protocolFolder + "/" + lastRev);
                retval.evaluateFolder(folderPath);

                // mencari metadata yang cocok (dari sisi current)
                for (int i = 0; i < retval.mMetadatas.size(); ++i) {
                    int found = -1;

                    Metadata current = retval.mMetadatas.get(i);
                    for (int j = 0; j < currentMetadata.size(); ++j){
                        if (currentMetadata.get(j).getFilePath().equals(current.getFilePath()) && currentMetadata.get(j).getFileType() != Utilities.TYPE_DELETED) {
                            found = j;
                            break;
                        }
                    }

                    // kalo lom pernah ada, skip aja
                    if (found == -1) continue;

                    // wah pernah ada, cek yuk yang ini baru pa ngga
                    Metadata prev = currentMetadata.get(found);

                    System.out.println("[Version control] prev = " + prev.getFilePath() + " " + prev.getChecksum());
                    System.out.println("[Version control] current = " + current.getFilePath() + " " + current.getChecksum());

                    if (prev.getChecksum().equals(current.getChecksum())) {
                        // wah sama nich, brarti versi nya samain ajah
                        current.setVersion(prev.getVersion());
                    } else {
                        // wah beda nich, beda versi berarti boy
                        current.setVersion(prev.getVersion() + 1);
                    }
                }

                // mencari file yang perlu didelete
                for (int i = 0; i < currentMetadata.size(); ++i) {
                    int found = -1;
                    
                    Metadata current = currentMetadata.get(i);
                    for (int j = 0; j < retval.mMetadatas.size(); ++j) {
                        // ingat, jangan compare file yang udah didelete sebelumnya
                        if (currentMetadata.get(j).getFilePath().equals(current.getFilePath()) && current.getFileType() != Utilities.TYPE_DELETED) {
                            found = j;
                            break;
                        }
                    }

                    // wah ketemu, udah pernah di kontrol berarti sebelumnya, skip aja gan
                    if (found != -1) continue;

                    // wah file ini perlu didelete nih, perlu di add ke list metadata sebagai deleted brarti
                    current.setFileType(Utilities.TYPE_DELETED);
                    retval.mMetadatas.add(current);
                }
            } catch (IOException iEx) {
                
            }
        }

        System.out.println("[Version Control] done generating version control");

        return retval;
    }

    public byte[] toSend() {
        int metadataCount = mMetadatas.size();
        StringBuilder sb = new StringBuilder();

        sb.append((char)((metadataCount >> 24) % 256));
        sb.append((char)((metadataCount >> 16) % 256));
        sb.append((char)((metadataCount >> 8) % 256));
        sb.append((char)(metadataCount % 256));

        for (int i = 0; i < metadataCount; ++i) {
            byte[] toSend = mMetadatas.get(i).toSend();

            for (int j = 0; j < toSend.length; ++j)
                sb.append((char)toSend[j]);
        }

        String str = sb.toString();
        byte[] retval = new byte[str.length()];

        for (int i = 0; i < retval.length; ++i)
            retval[i] = (byte)str.charAt(i);

        return retval;
    }

    public static VersionControl createFromByte(byte[] data) {
        VersionControl retval = new VersionControl();
        retval.setMetadatas(Metadata.readMetadatas(data));

        return retval;
    }

    public void evaluateFolder(String folderPath) {
        File file = new File(folderPath);
        String[] fileList = file.list();

        for (int i = 0; i < fileList.length; ++i) {
            if (fileList[i].equals(".ganteng")) continue;
            String filePath = folderPath + "/" + fileList[i];
            mMetadatas.add(Metadata.createNewMetadata(filePath));
            File newFile = new File(filePath);
            if (newFile.isDirectory())
                evaluateFolder(filePath);

        }
    }

    public void saveProtocolToFile(String folderPath, boolean newVersion) {
        File file = new File(folderPath + "/.ganteng");

        if (file.exists()) {
            String revList[] = file.list();

            if (revList.length == 0) {
                // create new revision folder
                mVersion = 1;
            } else {
                // evaluate existing
                String lastRev  = revList[revList.length - 1];
                mVersion        = Integer.parseInt(lastRev.substring(0, lastRev.indexOf(".")));
            }
        }
        
        int version = mVersion;

        if (newVersion)
            ++version;

        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(folderPath + "/.ganteng/" + version + ".teng"));

            int metadataCount = mMetadatas.size();

            bos.write((byte)((metadataCount >> 24) % 256));
            bos.write((byte)((metadataCount >> 16) % 256));
            bos.write((byte)((metadataCount >> 8) % 256));
            bos.write((byte)(metadataCount % 256));

            for (int i = 0; i < metadataCount; ++i)
                mMetadatas.get(i).writeMetadataToFile(bos);

            bos.close();
        } catch (IOException iEx) {
            
        }
    }

    public ArrayList<Metadata> getMetadatas() {
        return mMetadatas;
    }

    public void setMetadatas(ArrayList<Metadata> metadata) {
        mMetadatas = metadata;
    }

    private ArrayList<Metadata> mMetadatas;
    private int mVersion;
}
